﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Hardware.Meter.Hbm
{
    public class HBM : IMeter
    {
        /**
         *  001-柯力D2008F(tf=0)
            002-顶松DS822系列
            003-HBM
            004-耀华A9(tf=0)
            999-自定义协议
         * 
         */
        public bool IsOpen { get; set; }     //端口连接状态

        public int MessageLenth { get; set; }     //消息长度

        public int SleepTime { get; set; }       // 空闲时间

        public bool StickyPackage { get; set; }  // 粘包拆包

        public bool ShowHexFlag { get; set; } = false;      //显示Hex数据，缺省为假

        private byte[] remainData = null;

        public event EventHandle DataReceived;
        public event StatusEventHandle StatusChanged;
        public event EventShowHexData ShowHexData;

        public CommPort MeterSerialPort;

        private MeterParameter meterParamter;

        public HBM(MeterParameter _param, int _messageLength)
        {
            Settings.Port settings = new Settings.Port();
            settings.baudRate = _param.BaudValue;
            settings.dataBits = _param.DataBits;
            settings.parity = _param.parity;
            settings.stopBits = _param.stopBits;
            settings.portName = _param.ComName;
            MessageLenth = _messageLength;
            meterParamter = _param;
            SleepTime = _param.CharInterval;  //间隔时间

            MeterSerialPort = new CommPort(settings, SleepTime);
            MeterSerialPort.StatusChanged += Meter_StatusChanged;
            MeterSerialPort.DataReceived += Meter_DataReceived;            
        }

        public void Open()
        {
            try
            {
                MeterSerialPort.Open();
                IsOpen = MeterSerialPort.IsOpen;
                StatusChanged?.Invoke($"仪表连接:{meterParamter.ComName} {meterParamter.BaudValue} 成功!", this);
            }
            catch (Exception ex)
            {
                IsOpen = false;
                StatusChanged?.Invoke($"连接仪表:{meterParamter.ComName} {meterParamter.BaudValue} 异常:{ex.Message}", this);
            }
        }

        /// <summary>
        /// 关闭仪表
        /// </summary>
        public void Close()
        {
            if (MeterSerialPort != null)
            {
                if (IsOpen) MeterSerialPort.Close();
                MeterSerialPort = null;
            }
        }

        /// <summary>
        /// 根据不同的仪表，在此进行拆解出来，返回到前台
        /// 
        /// </summary>
        /// <param name="readBuffer"></param>
        /// <param name="sender"></param>
        private void Meter_DataReceived(byte[] readBuffer)
        {
            try
            {
                // 如果显示 Hex，发送 Hex 到仪表显示框中
                if (ShowHexFlag)
                {
                    ShowHexData?.Invoke(Utils.ByteArr2HexString(readBuffer));
                }
                // 分析接收到的数据
                AnalizeData(readBuffer);
            }
            catch (Exception ex)
            {                
                StatusChanged?.Invoke($"接收到仪表数据错误:{ex.Message}", this);
            }
        }

        private void Meter_StatusChanged(string param)
        {
            StatusChanged?.Invoke(param, this);
        }

        private int Find(byte[] data, byte b, int start = 0, int len = -1)
        {
            try
            {
                if (data == null) return -1;
                int i = 0;
                int ok_start = -1;
                if (len > 0) len = Math.Min(data.Length, len);
                else len = data.Length;
                for (i = start; i < len; i++)
                {
                    if (data[i] == b)
                    {
                        ok_start = i;
                        break;
                    }
                }
                return ok_start;
            }
            catch (Exception ex)
            {
                Debug.Print("Find:" + ex.Message);
                return -1;
            }
        }

        /// <summary>
        /// 分析仪表数据
        /// </summary>
        /// <param name="source"></param>
        private void AnalizeData(byte[] source)
        {
            try
            {
                if (DataReceived != null)
                {
                    if (source == null || source.Length == 0) return;
                    source = Utils.AddBytes(remainData, source);
                    int startPosition = -1;
                    byte[] readBuffer = null;                    

                    startPosition = Find(source, 0x00, 0);
                    if (startPosition == -1)
                    {
                        remainData = null;
                        return;
                    }
                    if (source.Length < MessageLenth)
                    {
                        remainData = Utils.GetData(source, startPosition);
                        return;
                    }
                    readBuffer = Utils.GetData(source, startPosition, MessageLenth);
                    if (readBuffer.Length == MessageLenth)
                    {
                        DataReceived?.Invoke(Hbm(readBuffer), this);
                    }
                    if (StickyPackage)
                    {
                        remainData = Utils.GetData(source, MessageLenth);
                    }
                    else
                    {
                        remainData = null;
                    }
                }
                else
                {

                }
            }
            catch (Exception)
            {

            }
        }

        private double Hbm(byte[] _buffer)
        {
            if (_buffer.Length != MessageLenth) return 0;
            try
            {
                byte firstFlag = _buffer[0];
                byte signFlag = _buffer[1];
                if (firstFlag.ToString("X2") == "00")
                {
                    byte[] net_weight = new byte[8];
                    //Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length
                    Array.ConstrainedCopy(_buffer, 2, net_weight, 0, 8);
                    string sNetWeight = Encoding.ASCII.GetString(net_weight);
                    long d_weight = 0;
                    if (signFlag.ToString("X2") == "20")
                    {
                        d_weight = Convert.ToInt64(sNetWeight);
                    }
                    else
                    {
                        // 2D
                        d_weight = -Convert.ToInt64(sNetWeight);
                    }
                    if (d_weight != 0)
                    {
                        return Utils.MeterUnitChange(d_weight, meterParamter.MeterUnit, meterParamter.SystemUnit);
                    }
                    else
                    {
                        return 0;
                    }
                }
                else
                {
                    return 0;
                }
            }
            catch (Exception ex)
            {
                StatusChanged?.Invoke("HBM仪表接收数据异常:" + ex.Message, this);
                return 0;
            }
        }

        //double weight = 0;
        //        switch (GlobalVariable.meter[meter_index].Type)
        //        {
        //            case 0: 
        //                weight = KeLiD2008(readBuffer, meter_index);                        
        //                break;
        //            case 1: 
        //                weight = Ds822(readBuffer, meter_index);                        
        //                break;
        //            case 2:
        //                weight = Hbm(readBuffer, meter_index);
        //                break;
        //            case 3:
        //                weight = YaoHuaA9TF0(readBuffer, meter_index);
        //                break;
        //            case 99:
        //                //三菱PLC返回的数据

        //                break;
        //            default:
        //                break;
        //        }

        //         switch (meterType)
        //                    {
        //                        case 0:
        //                        case 1:
        //                            startPosition = Find(source, 0x02, 0);
        //                            if (startPosition == -1)
        //                            {
        //                                remainData = null;
        //                                return;
        //                            }
        //    int endPosition = Find(source, 0x03, 0);
        //                            if (endPosition == -1)
        //                            {
        //                                remainData = GetData(source, startPosition);
        //                                return;
        //                            }
        //readBuffer = GetData(source, startPosition, dataLength);
        //                            if (readBuffer.Length == dataLength)
        //                            {
        //                                DataReceived?.Invoke(readBuffer, this);
        //                            }
        //                            if (stickyPackage)
        //                            {
        //                                remainData = GetData(source, endPosition + 1);
        //                            }
        //                            else
        //                            {
        //                                remainData = null;
        //                            }
        //                            break;
        //                        case 2:
        //                            startPosition = Find(source, 0x00, 0);
        //                            if (startPosition == -1)
        //                            {
        //                                remainData = null;
        //                                return;
        //                            }
        //                            if (source.Length<dataLength)
        //                            {
        //                                remainData = GetData(source, startPosition);
        //                                return;
        //                            }
        //                            readBuffer = GetData(source, startPosition, dataLength);
        //                            if (readBuffer.Length == dataLength)
        //                            {
        //                                DataReceived?.Invoke(readBuffer, this);
        //                            }
        //                            if (stickyPackage)
        //                            {
        //                                remainData = GetData(source, dataLength);
        //                            }
        //                            else
        //                            {
        //                                remainData = null;
        //                            }
        //                            break;
        //                        case 3:
        //                            startPosition = Find(source, 0x02, 0);
        //                            if (startPosition == -1)
        //                            {
        //                                remainData = null;
        //                                return;
        //                            }
        //                            int endByA9 = Find(source, 0x03, 0);
        //                            if (endByA9 == -1)
        //                            {
        //                                remainData = GetData(source, startPosition);
        //                                return;
        //                            }
        //                            readBuffer = GetData(source, startPosition, dataLength);
        //                            if (readBuffer.Length == dataLength)
        //                            {
        //                                DataReceived?.Invoke(readBuffer, this);
        //                            }
        //                            if (stickyPackage)
        //                            {
        //                                remainData = GetData(source, endByA9 + 1);
        //                            }
        //                            else
        //                            {
        //                                remainData = null;
        //                            }
        //                            break;
        //                        case 99:
        //                            //三菱PLC控制
        //                            DataReceived?.Invoke(source, this);
        //                            break;
        //                        default:
        //                            break;
        //                    }              
    }
}
